#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netdb.h>

#include "IOTCAPIs.h"
#include "AVAPIs.h"
#include "P2PCam/AVFRAMEINFO.h"
#include "P2PCam/AVIOCTRLDEFs.h"
#include "server.h"

extern char avID[10];
extern char avPass[10];

extern AV_Client gClientInfo[MAX_CLIENT_NUMBER];

extern char gVideoFn[128];
extern char gAudioFn[128];
extern int gProcessRun;
extern int gOnlineNum;
extern int gbSearchEvent;
//For DASA -- start
#ifdef DASA_ENABLED
extern int gDASALevel;
#endif
//For DASA -- end
extern SMsgAVIoctrlListEventResp *gEventList;
extern char gUID[21];
extern struct sockaddr_in gPushMsgSrvAddr;



#if 1
/********
  Thread - Send Video frames to all AV-idx
 */
void *thread_VideoFrameData(void *arg)
{
	unsigned int totalCnt = 0;
	float hF = 0.0, lF= 0.0, totalFps = 0;
	long takeSec = 0, takeUSec = 0, sendFrameRoundTick = 0;
	int fpsCnt = 0, round = 0, framerate = FPS, sleepTick = 1000000/framerate;
	int i = 0, avIndex = 0, bEnableVideo = 0, bSendFrameOut = 0, size = 0, ret = 0, lock_ret = 0;
	//For DASA -- start
#ifdef DASA_ENABLED
	int doCleanBuffer = 0, doCleanBufferDone = 0, waitKeyFrame = 0;    
#endif
	//For DASA -- start
	char buf[VIDEO_BUF_SIZE];
	struct timeval tv, tv2;
	struct timeval tStart, tEnd;
	FILE *fp = NULL;
	FRAMEINFO_t frameInfo;

	fp = fopen(gVideoFn, "rb");
	if(fp == NULL){
		printf("thread_VideoFrameData: Video File \'%s\' open error!!\n", gVideoFn);
		printf("[Vidio] is DISABLED!!\n");
		printf("thread_VideoFrameData: exit\n");
		pthread_exit(0);
	}

	// input file only one I frame for test
	size = fread(buf, 1, VIDEO_BUF_SIZE, fp);
	fclose(fp);
	if(size <= 0){
		printf("thread_VideoFrameData: Video File \'%s\' read error!!\n", gVideoFn);
		printf("[Vidio] is DISABLED!!\n");
		printf("thread_VideoFrameData: exit\n");
		pthread_exit(0);
	}	

	// *** set Video Frame info here *** 
	memset(&frameInfo, 0, sizeof(FRAMEINFO_t));
	frameInfo.codec_id = MEDIA_CODEC_VIDEO_H264;
	frameInfo.flags = IPC_FRAME_FLAG_IFRAME;

	printf("thread_VideoFrameData start OK\n");
	printf("[Video] is ENABLED!!\n");

	while(gProcessRun)
	{
		frameInfo.timestamp = getTimeStamp();
		bSendFrameOut = 0;
		takeSec = 0, takeUSec = 0, sendFrameRoundTick = 0;

		//For DASA -- start
#ifdef DASA_ENABLED
		if(gDASALevel == AV_DASA_LEVEL_QUALITY_HIGH){
			framerate = DASA_HIGH_FPS;
			sleepTick = 1000000/framerate;
		}
		else if(gDASALevel == AV_DASA_LEVEL_QUALITY_BTWHIGHNORMAL){
			framerate = DASA_BTWHIGHNORMAL_FPS;
			sleepTick = 1000000/framerate;
		}
		else if(gDASALevel == AV_DASA_LEVEL_QUALITY_NORMAL){
			framerate = DASA_NORMAL_FPS;
			sleepTick = 1000000/framerate;
		}
		else if(gDASALevel == AV_DASA_LEVEL_QUALITY_BTWNORMALLOW){
			framerate = DASA_BTWNORMALLOW_FPS;
			sleepTick = 1000000/framerate;
		}
		else if(gDASALevel == AV_DASA_LEVEL_QUALITY_LOW){
			framerate = DASA_LOW_FPS;
			sleepTick = 1000000/framerate;
		}
#endif
		//For DASA -- end

		if(fpsCnt == 0)
			gettimeofday(&tv, NULL);

		for(i = 0 ; i < MAX_CLIENT_NUMBER; i++)
		{
			//get reader lock
			lock_ret = pthread_rwlock_rdlock(&gClientInfo[i].sLock);
			if(lock_ret)
				printf("Acquire SID %d rdlock error, ret = %d\n", i, lock_ret);

			avIndex = gClientInfo[i].avIndex;
			bEnableVideo = gClientInfo[i].bEnableVideo;
			//For DASA -- start
#ifdef DASA_ENABLED
			doCleanBuffer = gClientInfo[i].doCleanBuffer;
			doCleanBufferDone = gClientInfo[i].doCleanBufferDone;
			waitKeyFrame = gClientInfo[i].waitKeyFrame;
#endif
			//For DASA -- end

			//release reader lock
			lock_ret = pthread_rwlock_unlock(&gClientInfo[i].sLock);
			if(lock_ret)
				printf("Acquire SID %d rdlock error, ret = %d\n", i, lock_ret);

			if(avIndex < 0 || bEnableVideo == 0){
				continue;
			}

			//For DASA -- start
#ifdef DASA_ENABLED
			if(doCleanBuffer && !doCleanBufferDone){
				//printf("SID[%d] avIndex[%d] doCleanBuffer[%d] doCleanBufferDone[%d]\n", i, avIndex, doCleanBuffer, doCleanBufferDone);
				continue;
			}

			if(waitKeyFrame){
				if(frameInfo.flags == IPC_FRAME_FLAG_PBFRAME){
					continue;
				}
				else{
					lock_ret = pthread_rwlock_wrlock(&gClientInfo[i].sLock);
					if(lock_ret)
						printf("Acquire SID %d rwlock error, ret = %d\n", i, lock_ret);

					gClientInfo[i].waitKeyFrame = 0;

					//release lock
					lock_ret = pthread_rwlock_unlock(&gClientInfo[i].sLock);
					if(lock_ret)
						printf("Release SID %d rwlock error, ret = %d\n", i, lock_ret);
				}
			}
#endif
			//For DASA -- end

			// Send Video Frame to av-idx and know how many time it takes
			frameInfo.onlineNum = gOnlineNum;
			gettimeofday(&tStart, NULL);
			
			int ftype = 0;
                        BUFFERDATA_t *p = get_ele();
                        if (p == NULL)
                        {
 //                          printf("hold on\r\n");
                           usleep(10000);
                           continue;
                        }


                        if (p->ftype)
                                frameInfo.flags = IPC_FRAME_FLAG_IFRAME;
                        else
                                frameInfo.flags = IPC_FRAME_FLAG_PBFRAME;


			ret = avSendFrameData(avIndex, p->buf, p->size, &frameInfo, sizeof(FRAMEINFO_t));
			gettimeofday(&tEnd, NULL);

                        free(p->buf);
                        free(p);
			
			takeSec = tEnd.tv_sec-tStart.tv_sec, takeUSec = tEnd.tv_usec-tStart.tv_usec;
			if(takeUSec < 0)
			{
				takeSec--;
				takeUSec += 1000000;
			}
			sendFrameRoundTick += takeUSec;
			totalCnt++;

			if(ret == AV_ER_EXCEED_MAX_SIZE) // means data not write to queue, send too slow, I want to skip it
			{
				usleep(10000);
				continue;
			}
			else if(ret == AV_ER_SESSION_CLOSE_BY_REMOTE)
			{
				printf("thread_VideoFrameData AV_ER_SESSION_CLOSE_BY_REMOTE SID[%d]\n", i);
				unregedit_client_from_video(i);
				continue;
			}
			else if(ret == AV_ER_REMOTE_TIMEOUT_DISCONNECT)
			{
				printf("thread_VideoFrameData AV_ER_REMOTE_TIMEOUT_DISCONNECT SID[%d]\n", i);
				unregedit_client_from_video(i);
				continue;
			}
			else if(ret == IOTC_ER_INVALID_SID)
			{
				printf("Session cant be used anymore\n");
				unregedit_client_from_video(i);
				continue;
			}
			//For DASA -- start
#ifdef DASA_ENABLED
			else if(ret == AV_ER_DASA_CLEAN_BUFFER)
			{
				printf("avIndex[%d] need to do clean buffer\n", avIndex);
				lock_ret = pthread_rwlock_wrlock(&gClientInfo[i].sLock);
				if(lock_ret)
					printf("Acquire SID %d rwlock error, ret = %d\n", i, lock_ret);

				gClientInfo[i].doCleanBuffer = 1;
				gClientInfo[i].doCleanBufferDone = 0;
				gClientInfo[i].waitKeyFrame = 1;

				//release lock
				lock_ret = pthread_rwlock_unlock(&gClientInfo[i].sLock);
				if(lock_ret)
					printf("Release SID %d rwlock error, ret = %d\n", i, lock_ret);
			}
#endif
			//For DASA -- end
			else if(ret < 0)
				printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n");

			bSendFrameOut = 1;
		}

		if(bSendFrameOut && fpsCnt++ >= framerate)
		{
			round++;
			gettimeofday(&tv2, NULL);
			long sec = tv2.tv_sec-tv.tv_sec, usec = tv2.tv_usec-tv.tv_usec;
			if(usec < 0)
			{
				sec--;
				usec += 1000000;
			}
			usec += (sec*1000000);

			long oneFrameUseTime = usec / fpsCnt;
			float fps = (float)1000000/oneFrameUseTime;
			if(fps > hF) hF = fps;
			if(lF == 0.0) lF = fps;
			else if(fps < lF) lF = fps;
			printf("Fps = %f R[%d]\n", fps, round);
			fpsCnt = 0;
			totalFps += fps;
		}

		// notice the frames sending time for more specific frame rate control
		if( sleepTick > sendFrameRoundTick )
			usleep(sleepTick-sendFrameRoundTick);
	}

	printf("[thread_VideoFrameData] exit High/Low [%f/%f] AVG[%f] totalCnt[%d]\n", hF, lF, (float)totalFps/round, totalCnt);

	pthread_exit(0);
}
#endif




